Copyright □ 1999, by Professor Jong-Hwan Kim, Korea Advanced Institute of Science and Technology (KAIST).  All rights reserved. Reproduction or translation of any part of this work is unlawful. Request for permission or further information should be addressed to Professor Jong-Hwan Kim at <johkim@vivaldi.kaist.ac.kr> or <Tel: +82-42-869-3448>.

Prof. Jong-Hwan Kim	Intelligent Control Lab, KAIST

3.마이크로컨트롤러

3.1 마이크로컨트롤러

로봇 시스템을 구성하는 여러 부분들 중에서 가장 중요한 부분을 고른다면 로봇의 두뇌라 말할 수 있는 연산처리 부분을 선택할 수 있다. 하드웨어적으로는 마이크로컨트롤러(Micro-controller) 보드를 말한다. 로봇이 축구 경기를 하기 위해서는 각각의 로봇들이 자신의 움직임을 제어하고, 상황을 판단할 수 있는 지능을 가져야 한다. 로봇이 지능을 갖기 위해서는 프로그램을 내장하고, 프로그램을 연산 처리할 수 있는 하드웨어가 필요한 것이다. 마이크로 컨트롤러는 로봇 시스템의 지능을 나타내는 부분이며 사람에게 있어서 머리에 해당되는 부분이다.

로봇 기반 축구 로봇 시스템에 있어서 마이크로컨트롤러에서 처리해야 하는 일은 많다. 이 부분에서는 주로 통신부를 통해서 받은 데이터를 가지고 모터 제어를 한다. 로봇 시스템은 호스트 컴퓨터에서 보내준 데이터를 마이크로컨트롤러의 직렬단자(serial pin)를 통해서 통신부로부터 받는다. 이 데이터를 가지고 로봇 시스템의 모터구동을 위한 연산을 하고 연산된 결과를 모터 구동부에 전달한다. 원격 지능형 축구로봇 시스템에서는 호스트 컴퓨터에서 보낸 데이터가 모터 제어를 위한 모터의 속도 데이터이면 연산이 필요하지 않다. 하지만 지능 내재형 축구로봇 시스템에서는 로봇의 좌표와 방향각, 공의 좌표가 호스트 컴퓨터에서 보내준 데이터가 되므로  모터 제어를 위해서는 여러 연산 과정이 필요하다. 마이크로컨트롤러 보드를 설계하기에 앞서 먼저 고려해야할 사항들이 몇 가지 있다. 구성하고자 하는 로봇의 전체적인 기능과 원하는 연산 속도, 보드의 크기 등이 그것이다. 로봇 축구를 하는데 있어서 빠른 연산속도는 필수적이며, 기능이 많아질수록 마이크로 컨트롤러 보드의 크기가 커진다는 점도 고려해야 한다. 마이크로컨트롤러 보드를 설계하기 위해서는 기본적으로 마이크로컨트롤러가 어떻게 동작하는지를 이해해야 한다. 기본 동작을 이해하면 마이크로컨트롤러 보드의 기본 구조를 쉽게 설계할 수 있다. 실제로 보드를 설계할 경우에는 개념에 의한 설계도 중요하지만 경험을 바탕으로 한 설계 또한 중요하다. 본 절에서는 마이크로컨트롤러 보드 설계의 전반적인 내용을 다루고자 한다.

3.2 마이크로컨트롤러의 기본 동작

기본 동작은 크게 4 가지의 과정으로 나누어 생각할 수 있다. 즉, 리셋, 명령 읽기, 실행, 인터럽트이다. 각각의 과정에 대해서 어떤 동작이 이루어지는지 간단히 살펴보자.

□ 리셋(reset): 리셋이 걸리게 되면 해당 레지스터에 값을 설정하여 내부 핀의 기능들을 정해진 값으로 초기화한다. 그 후 프로그램 카운터(program counter)를 리셋 벡터로 설정하여 그 번지부터 프로그램을 실행할 준비를 한다. 참고로 프로그램 카운터는 바로 다음에 실행할 명령어의 주소를 가지고 있는 레지스터를 말한다.

□ 명령어 읽기(fetch): 명령을 읽어오는 과정은 프로세서마다 다르지만 일반적으로 4개의 단계로 구성된다. 먼저 명령을 읽어올 주소를 주소 버스(address bus)에 저장하고, 읽기 제어 신호(RD)를 제어 버스에 준비한다. 데이터가 준비되었는지를 확인한 후, 마지막으로 메모리로부터 데이터를 읽어들인다. 참고로 한 단계는 하나의 상태 시간을 소요하며, 하나의 상태 시간은 보통 2개 또는 3개의 클럭 신호로 구성된다.

□ 실행(execute): 명령을 실행하기에 앞서 앞에서 언급했듯이 먼저 메모리로부터 명령을 읽어 내부 명령 레지스터(IR)로 가져오는 과정(fetch)을 수행한다. 그 후 명령을 해독(decode)하고, 해독한 명령을 실제로 실행(execute)하는 과정을 거치게 된다.

□ 인터럽트(interrupt): 프로그램을 순차적으로 실행하는 도중에 현재의 작업중인 일보다 우선 순위가 더 높은 일이 발생할 경우, 인터럽트가 걸리게 된다. 일단 인터럽트 요청이 발생하면 현재 실행하고 있던 프로그램을 중단하고 현재의 상태를 모두 스택(stack)에 저장시킨다. 그 후 프로그램 카운터(PC)를 인터럽트 벡터로 설정하여 인터럽트 처리 루틴의 위치로 점프한 후, 처리 루틴을 실행한다. 인터럽트 처리 루틴의 실행이 모두 끝나면 스택에 저장되어 있던 내용을 모두 읽어들인 후, 다시 원래의 프로그램을 실행시키게 된다.

위에서 설명한 마이크로컨트롤러의 기본 동작의 흐름을 나타내면 그림 3.1과 3.2와 같다.

그림 3.1 마이크로컨트롤러의 기본동작

그림 3. 인터럽트 처리과정

3.2.1 마이크로컨트롤러 보드의 기본구조

앞 절에서 설명한 마이크로컨트롤러의 기본 동작을 이해하면, 마이크로컨트롤러 보드의 기본 구조는 쉽게 예상할 수 있다. 그림 3.3은 일반적인 기본 구조의 한 예를 나타낸다.

그림 3.3은 외부에 메모리를 연결한 경우를 나타낸다. 프로그램 메모리로 롬(ROM)이 필요하고, 데이터 메모리로 램(RAM)이 필요하다. 또한 롬과 램을 읽고 쓰기 위한 읽기/쓰기(read/write) 신호가 각각 입력되어야 하며, 롬과 램 중 어떤 칩의 데이터를 읽거나 쓸 것인지를 칩 셀렉터(chip-selector)를 달아 선택해 주어야 한다. 즉, 칩 셀렉터는 하나의 칩에만 허용(enable) 신호를 보내 해당 칩만 동작하도록 하고, 나머지는 동작하지 않도록 하는 역할을 하게 된다. 칩 셀렉터가 없다면 여러 칩들의 데이터 버스가 동시에 선택되어 원치 않는 동작을 일으키게 된다.

그림 .3 마이크로컨트롤러 보드의 기본 구조

롬과 램의 용량은 구현할 프로그램의 용량과 데이터의 양을 먼저 어느 정도 예상한 후 그 보다 두 배 정도를 잡으면 적당할 것이다. 참고로 만일 마이크로컨트롤러가 내부에 롬을 포함하고 있고, 그 용량도 부족하지 않다면 외부에 따로 메모리를 연결하지 않아도 된다. 또한 마이크로컨트롤러에 칩 셀렉터가 내장되어 있다면 따로 칩 셀렉터를 달지 않고, 마이크로컨트롤러의 칩 셀렉터 신호를 사용하면 된다. 예를 들면, 80C196의 경우에는 내부에 내장된 롬, 칩 셀렉터가 없기 때문에 외부에 연결해야하고, 89C52는 8K 롬이 내장되어 있어 외부 롬을 사용하지 않아도 된다.

그림 3.3은 가장 간단한 구조를 나타낸 것이고, 실제로 축구 로봇에 사용할 마이크로컨트롤러 보드를 구현할 경우에는 다른 여러 가지 기능을 갖는 회로를 추가해야 한다. 모터 제어 회로, 무선 통신 회로 등과 인터페이싱이 필요하다. 마이크로컨트롤러 보드 설계 시 다른 보드와의 입출력을 고려하여 커넥터를 적절한 위치에 배치하는 것이 중요하고, 만일의 경우를 위해 주소 버스와 데이터 버스는 커넥터로 연결해 놓는 것이 유리하다. 또한 안정된 보드를 설계하기 위해서는 각 칩의 VCC, GND 사이에 0.1□F ∼ 10□F 정도의 콘덴서를 달아주고, 외부와의 전원이 입출력되는 단자에는 용량이 큰 콘덴서를 달아주는 것이 좋다.

3.2.2 주소와 데이터 버스

일반적으로 8 비트 마이크로컨트롤러의 데이터 버스는 주소 버스의 하위 비트와 같은 핀을 사용한다. 즉, 마이크로컨트롤러의 같은 핀에서 데이터도 출력되고 주소도 출력된다. 따라서 데이터 신호와 주소 신호를 분리하는 회로가 필요하다. 이것은 데이터와 주소가 출력되는 타이밍이 다르기 때문에 가능하며, 주소 값이 출력될 경우 함께 출력되는 ALE(Address Latch Enable) 제어 신호를 이용하면 쉽게 구현할 수 있다. 데이터 버스와 주소 버스를 분리하는 회로는 그림 3.4와 같다.

그림 3. 주소 버스와 데이터 버스의 분리

마이크로컨트롤러는 먼저 지정하고자 하는 곳의 주소를 ALE 신호와 함께 먼저 출력 한다. 그 후 해당 데이터를 출력하거나 받아들이게 되는데, 이때 ALE 신호는 출력이 되지 않기 때문에 래치(latch)는 입력을 받아들이지 않게 되고, 이전에 입력받았던 주소의 하위 8 비트만 출력값을 유지하게 된다. 따라서 주소 버스와 데이터 버스는 충돌 없이 분리된 동작이 가능해 진다.

3.2.3 칩 셀렉터(selector)의 구현

칩 셀렉터는 앞에서 언급한 바와 같이 선택된 칩에 허용(enable) 신호를 보내어, 그 칩만 동작하고 나머지 칩들은 동작하지 않도록 한다. 참고로 AM188이나 80296과 같은 마이크로컨트롤러는 칩 셀렉터를 내장하고 있다. 칩 셀렉터의 입력으로는 RD, WR와 같은 제어 신호, 주소 버스 등이 사용될 수 있고, 출력으로는 칩 선택 신호가 나온다. 이 때 마이크로컨트롤러 이외에 추가로 포함시키는 칩의 개수만큼 칩 선택 신호가 출력되어야 한다. 예를 들어 그림 3.3과 같은 기본 구조만을 사용한다면 칩 선택 신호는 램과 롬에 각각 하나씩 해서 총 2개만 있으면 된다.

그림 3. 칩 셀렉터의 입출력 관계

일반적으로 주소는 상위 비트부터 사용한다. 예를 들어 주소 8 비트를 입력으로 사용한다면, 주소 버스가 A0 - A15 라 가정할 경우 A15, A14, A13, ... , A9, A8 비트를 이용한다.

칩 셀렉터로는 디코더를 직접 사용하기도 하지만, 일반적으로는 PAL(programmable array logic) 이나 GAL(generic array logic)과 같이 프로그래밍 가능한 소자를 사용한다. 참고로, PAL은 한 번만 프로그래밍 할 수 있고, GAL은 여러 번 프로그래밍이 가능하다.

PAL이나 GAL을 위한 프로그램은 사용하는 컴파일러에 따라 형식이 약간씩 다르다. 다음은 회로의 원하는 메모리 지도와 이를 구현하기 위한 칩 셀렉터의 프로그램 중 논리식 부분만을 나타낸 것이다. 그림 3.5에서 칩 셀렉터는 입력으로 A15 - A8의 주소와 제어 신호 RD(read)를 받아들이고, 출력으로는 램(RAM), 롬(ROM), PPI, 카운터1, 카운터2의 칩 선택 신호를 갖는다. 참고로 논리식에서 '!'는 논리 NOT을 의미한다. 다음은 그림 3.5에서 구현된 Equations에서 한 부분을 예를 들어 설명한 것이다(컴파일러에 따라 논리식의 표현 형식은 약간 달라질 수 있다).

3.2.4 클럭(clock)

마이크로컨트롤러의 내부 구조에서 언급한 바와 같이 마이크로컨트롤러는 내부의 클럭 발생기에 의해 생성되는 클럭에 맞추어 동작하게 된다. 즉, 이 클럭 주파수에 따라서 마이크로컨트롤러의 처리 속도가 결정된다. 이 때 클럭의 주파수를 결정하는 방법에는 두 가지가 있다. 그림 6은 클럭 주파수를 결정하는 두 가지 방법을 나타내고 있으며, 대부분의 마이크로컨트롤러는 두 가지 방법 중 선택해서 사용할 수 있도록 설계되어 있다.

그림 3.6의 첫 번째 방법은 외부에 원하는 주파수의 크리스탈을 달아 내부의 클럭 발생기에서 해당 주파수를 발진하도록 하는 방법이고, 두 번째 방법은 외부에 따로 오실레이터를 달아 XTAL1으로 입력되는 클럭을 그대로 마이크로컨트롤러 내부에서 사용하는 방법이다. 즉, 두 번째 방법은 마이크로컨트롤러에 내장되어 있는 발진기는 사용하지 않는 것이다. 이 방법은 보드 내의 여러 칩 클럭을 하나로 할 때 사용한다.

그림 3.6 클럭 주파수 결정 방법

3.2.5 인터페이스(Interface) 방법

기본 구조 외에 원하는 기능을 위해 다른 칩을 추가로 연결할 경우에는 몇 가지만 고려해 주면 쉽게 구현이 가능하다. 먼저 추가되는 칩에서 필요로 하는 주소의 비트 수와 데이터 비트 수를 알아보고, 칩의 선택 신호가 로우-동작(low-active)인지 아니면 하이-동작(high-active)인지를 확인한다. 또한 리셋은 소프트웨어적으로 걸어야 하는지 아니면 보드의 하드웨어 리셋을 걸어야 하는지를 파악한다. 그 후 그림 3.7과 같이 연결하면 된다.

그림 3.7 일반적인 인터페이스 방법

그림 3.7은 데이터 8 비트, 주소 2 비트 그리고 제어 신호로 RD, WR을 필요로 하는 경우의 칩을 나타낸 것이다. CS는 칩 셀렉터로부터 출력되는 칩 선택 신호이고, reset은 칩을 초기화 하는 입력 신호이다.

아날로그 소자를 연결하고자 할 때 가장 중요하게 고려해야할 사항은 전류이다. 아날로그 소자는 대부분 많은 전류를 필요로 하기 때문에 따로 구동 회로를 구현해 주는 것이 안전하다. 만약 디지털 소자의 출력 핀에 바로 아날로그 소자를 연결할 경우, 아날로그 소자에서 순간 많은 전류를 소모하게 되면 칩의 전류 구동 능력이 미치지 못해 전압이 떨어지게 되어 오동작을 일으키는 요인이 된다. 많은 전류를 구동하기 위해서는 파워 트랜지스터 등을 이용하면 가능할 것이다.

3.3 PIC16C73

로봇 축구를 위해서는 마이크로컨트롤러 보드가 로봇의 성능을 좌우하지만 아주 단순한 기능을 갖고서도 축구를 할 수 있다. 즉, 로봇들이 호스트 컴퓨터에서 보내주는 통신 데이터를 받아서 모터를 제어하는 일을 할 수 있으면 축구를 위한 기본 기능을 갖춘 셈이다. 로봇 축구 종목 중에 하나인 NaroSot의 경우는 로봇의 크기가 [eqn: 4cm times 4cm times 5.5cm{}]로 제한되어 있어서 로봇들이 많은 기능을 가지고 있기는 힘들다. 이 경우도 호스트 컴퓨터에서 보내는 데이터를 받아서 모터를 제어하는 기능만 가진다. 모터제어를 위해서는 마이크로컨트롤러 내부에 PWM(Pulse Width Modulation)기능을 내장하고 있어야 한다. 그리고 컨트롤러내부에 프로그램을 위한 메모리를 가지고 있으면 단순한 기능을 가진 축구로봇의 구현이 쉽게된다. 이에 적합한 원 칩 마이크로컨트롤러로는 여러 가지 종류가 있지만 여기서는 PIC16C73에 대해서 다루겠다.

PIC16C73/73A는 192 바이트의 램, 22개의 I/O 핀을 가지고 있으며 3개의 timer/counter와2개의 Capture/Compare/PWM module이 있다. 그리고 USART(Universal Synchronous Asynchronous Receiver Transimitter)을 위한 serial port와 5채널의 8비트 A/D converter가 있다. 그림 3.8에 핀들을 나타내었고 여기서는 핀들의 기능에 대해서 간단히 살펴보자.

그림 3.8 PIC16C73의 핀구조

OSC1/CLKIN : 입력, 오실레이터 접속 혹은 외부 클럭 소스 입력

OSC2/CLKOUT : 오실레이터 접속 혹은 CLKOUT 출력

[eqn: bar{rmMCLR{}}] : 엑티브 □L", 마스터 클리어(리셋)

RA0[eqn: SIM]RA5 : 포트 A의 양방향 I/O 포트, TTL 레벨, A/D converter를 위한 입력으	로도 사용된다.

RB0[eqn: SIM]RB7 : 포트 B의 양방향 I/O 포트, TTL 레벨, 입력으로 사용할 경우 내부적	으로 약한 풀업이 될수 있도록 소프트웨어로 프로그래밍이 가능하다.

RC0[eqn: SIM]RC7 : 포트 C의 양방향 I/O 포트, TTL 레벨, RC1은 PWM신호 출력인	CCP2로도 사용된다. RC2는 PWM 신호 출력인 CCP1으로도 사용된다.

[eqn: rm V_SS, V_DD] : 전원([eqn: rm V_SS] : 접지, [eqn: rm V_DD] : +5V)

이들 중에서 모터제어를 하기 위해서 PWM 신호를 발생시키는 방법과  USART를 통해서 통신을 하는 법에 대해 살피자.

3.3.1 PWM 신호 발생

CCP1을 PWM 신호 출력으로 사용하기 위해서는 PORTC의 control register인 TRISC<2>를 0으로 설정한다. 여기서 <2>는 2번째 비트를 나타낸다. PWM 신호의 주기를 결정하는 요소는 PR2 값과 TMR2 prescale 값이다.

[eqn: rmPWM ~period = (PR2+1) CDOT 4 CDOT T_OSC CDOT(TMR2~prescale ~value)]

PWM 주파수는 1/(PWM period) 이다. PWM의 duty cycle은 CCPR1L 레지스터와 CCP1CON<5:4>로서 결정되며 CCP1CON<5:4>는 CCP1CON의 5번째와 4번째 비트를 나타낸다.즉, CCPR1L은 8비트의 상위비트를 결정하고 CCP1CON<5:4>는 하위 LSB를 결정한다. 주어진 PWM 주파수에 대해 최대 PWM resolution은 다음과 같다.

[eqn: rm Resolution~=~{log({F_OSC }over{F_PWM})} over {log(2)} ~bits]

만일 전체 PWM의 resolution이 8비트라면 duty cycle이 255보다 큰 값들은 100%의 duty cycle 이다.

예)

원하는 PWM 주파수 = 78.125KHz

Fosc = 20MHz

TMR2 prescale = 1

이를 위해 설정해야 하는 PR2 값과 PWM의 resloution은 얼마인가?

1/78.125KHz = [(PR2)+1][eqn: cdot]4[eqn: cdot]1/20MHz[eqn: cdot]1

12.8[eqn: mu s]	= [(PR2)+1][eqn: cdot]4[eqn: cdot]50 ns[eqn: cdot]1

PR2	= 63

1/78.125KHz = [eqn: 2^{rm PWM {}resolution} CDOT]1/20MHz[eqn: cdot]1

12.8[eqn: mu s]      = [eqn: 2^{rm PWM {}resolution} CDOT]50ns[eqn: cdot]1

256	= [eqn: 2^{rm PWM {}resolution}]

log(256)	= (PWM resolution)[eqn: cdot]log(2)

8.0	= PWM resolution

즉, 20MHz의 oscillator를 사용할 경우 8비트 resolution의 duty cycle를 갖는	78.125KHz의 PWM신호를 만들 수 있다. 8비트 resolution의 duty cycle 이므로	[eqn: 0~<=rm CCPR1L:CCP1CON<5:4><={}255] 이다. 만일 255이상의 값에서는 100%의	duty	cycle를 가진다.

PWM 신호를 발생시키기 위해서는 다음과 같은 과정으로 한다.

(가) PR2 레지스터의 값을 설정함으로써 PWM 주기를 결정한다.

(나) CCPR1L과 CCP1CON<5:4>에 값을 써 줌으로써 PWM duty cycle를 결정한다.

(다) TRISC<2> 비트를 0으로 설정함으로써 CCP1을 출력으로 만든다.

(라) TMR2 prescale value 값을 설정하고 T2CON 레지스터를 이용하여 Timer2를 enable로 만든다.

CCP2에 대해서는 CCP1처럼 설정해주면 된다. 이때는 duty cycle를 결정하기 위해서 CCPR2L과 CCP2CON<5:4>를 이용한다.

실제 프로그램에서는 위에서 설명한 방법을 이용하여 만들어진 함수를 사용한다. 다음은 실제 로봇내에 들어가는 프로그램에서 PWM 신호에 관련된 부분을 설명한다.

/***************  프로그램 예제 ***************/

unsigned long pwm1, pwm2;	/* 변수 선언 */

pwm1 = 0x01fc;	/* 초기값 설정 */

pwm2 = 0x01fc;

OpenPWM1(0x0ff); // 11.0592MHz: period = 10.8KHz

/* OpenPWM1 함수 이용 */

OpenPWM2(0x0ff); // 11.0592MHz: period = 10.8KHz

T2CON.TMR2ON = 1;	/* Timer 2를 Enable */

SetDCPWM1(pwm1);	/* pwm1 값으로 설정 */

SetDCPWM2(pwm2);

/***************  함수 설명  ***************/

void OpenPWM1(unsigned char period)

{

CCPR1L = 0x00;	// Power on reset(POR) for duty cycle

CCP1CON = 0x0F;	// PWM for CCP1

PR2 = period;	// Set period

TRISC.CCP1 = 0;	// Set ouput

}

void SetDCPWM1(unsigned long duty_cycle)

{

CCPR1L = duty_cycle >> 2;	// Place 8 MSbs in CCPR1L

duty_cycle = (duty_cycle << 4) & 0x30;	// Place 2 LSbs in CCP1CON

CCP1CON = CCP1CON | duty_cycle;

}

3.3.2 USART를 이용한 통신

Baud rate를 설정하기 위해 BRGH와 SPBRG 값을 정한다. 로봇 축구에서는 호스트 컴퓨터에서 로봇들에게 명령을 전달할 때는 비동기방식의 통신을 한다. BRGH에 따라 다음과 같다.

BRGH = 0(Low Speed)	BRGH = 1(High Speed)
Baud rate =[eqn: rmF_OSC]/(64(X+1))	Baud rate =[eqn: rmF_OSC]/(16(X+1))

X = SPBRG 의 값(0[eqn: SIM]255)

예)

[eqn: rmF_OSC] = 16MHz

원하는 Baud rate = 9600bps

BRGH = 0

이를 위한 SPBRG의 값 X는 얼마인가?

Desired Baud rate = [eqn: rmF_OSC]/(64(X+1))

9600	=  16000000/(64(X+1))

X	=  25.042 [eqn: SIMEQ] 25

Calculated Baud rate = 16000000/(64(25+1)) = 9615

SPBRG의 값을 25로 설정했을 때 원래의 Baud rate와 오차는 다음과 같다.

Error = (Calculated Baud rate-Desired Baud rate)/(Desired Baud rate)

= (9615-9600)/9600 = 0.16%

이 정도의 오차는 무시할 만하다.

로봇은 호스트 컴퓨터에서 보내준 데이터를 받아서 이를 처리한다. 이때 마이크로 컨트롤러의 인터럽트를 이용하여 데이터를 받는 방식과 항상 데이터를 받을 준비를 하다가 데이터가 오면 이를 받아서 처리하는 방법 2가지가 있다. 여기서는 후자의 방법에 대해 살핀다. TXSTA(Transmit status and control) 레지스터에서 BRGH 비트, SYNC 비트, TXEN 비트, TX9 비트를 설정해야 한다. 8비트 데이터 통신을 위해서 TX9 = 0, 송신을 하기 위해서 TXEN = 1, SYNC=1,BRGH는 0 또는 1로 설정한다. RXSTA(Receive status and control)레지스터에서는 SPEN(Serial port enable) = 1, RX9 = 0, CREN(Continuous receive enable bit) = 1로 설정한다.

다음은 USART를 이용한 프로그램 예제이며 여기서도 위에서 설명한 방법을 이용한 함수들을 사용한다.

/***************  프로그램 예제 ***************/

main()

{

unsigned char config, flag, ch;	/* 변수 선언 */

config = RX_INT_OFF & TX_INT_OFF & USART_ASYNCH_MODE &	USART_TX_RX_MODE&USART_LO_SPEED & USART_EIGHT_BIT	& USART_CONT_RX;	/* config 값 설정 */

OpenUSART(config, 8); // 11.0592MHz: 19200bps

/* OpenUSART 함수를 이용 */

ch = getch();

[eqn: DOTSLOW DOTSLOW DOTSLOW DOTSLOW DOTSLOW DOTSLOW]

}

unsigned char getch()

{

while(!DataRdyUSART());	/* DataRdyUSART() 의 return 값이

return(getcUSART());	1일 때 USART에서 데이터를 받는다 */

}

/***************  함수 설명  ***************/

void OpenUSART(bits config, unsigned char baud)

{	/* config bit에 따라서 각 레지스터                                                       값들을 설정 */

RCSTA = 0;	// POR(Power on reset) Values

TXSTA = 0;

PIE1.RCIE = 0;	// USART receive interrupt enable bit

PIE1.TXIF = 0;	// USART transmit interrupt enable bit

SPBRG = baud;	// Set Baud Rate

baud = RCREG;	// POR (Clear RCIF INT)

if (config.0)	// CONTINUOUS RX

RCSTA.CREN = 1;

else

RCSTA.SREN = 1;

if (config.1)	// NINE BIT

{

TXSTA.TX9 = 1;

RCSTA.RX9 = 1;

}

if (config.2)	// HIGH SPEED

TXSTA.BRGH = 1;

if (config.3)	// TX & RX ENABLED

{

TXSTA.TXEN = 1;

TRISC.TX = 0;

}

TRISC.RX = 1;

if (config.4)	// SYNC MASTER MODE

TXSTA.CSRC = 1;

if (config.5)	// SYNC MODE

TXSTA.SYNC = 1;

if (config.6)

PIE1.TXIE = 1;

if (config.7)

PIE1.RCIE = 1;

RCSTA.SPEN = 1;	// Enable Serial Port

}

unsigned char DataRdyUSART(void)

/* Data를 받을 준비가 되었는지를 조사하는 함수 */

{

if (PIR1.RCIF)	// This is more efficient than returning flag

return 1;

else

return 0;

}

void getsUSART(unsigned char near *buffer, unsigned char length)

{	/* 수신 버퍼로 데이터를 가져옴 */

char i;	// Buffer length counter

for (i = 0; i < length ; i++)

{

while(!DataRdyUSART());	// Wait for data ready

*buffer = getcUSART();	// Store RX data

buffer++;	// Increment pointer

}

}

예제 프로그램에서 사용된 각 레지스터 이름과 기능은 PIC16C73의 매뉴얼에서 참조한다.

이밖에도 로봇들의 고유번호를 설정하기 위해 포트를 이용한다. PORTB가 소프트웨어적으로 내부 풀업이 가능하고 이는 OPTION.RBPU = 0으로 설정하면 된다. 내부 풀업을 소프트웨어적으로 설정을 하면 외부에 따로 추가적인 부품(저항)이 들어가지 않는 장점이 있다. 로봇의 고유번호를 인식하기 위해 할당된 PORTB의 각 비트 값들을 조사하여 로봇의 고유번호를 지정한다.

/***************  프로그램 예제  ***************/

#define SW1      PORTB.7	/* SW1을 PORTB의 7번째 핀으로 설정 */

#define TEAM_A   0x0f

#define TEAM_B   0xf0

TRISB = 0b11110000;	/* Port B중에서 7[eqn: sim]4비트 까지는 입력,

3[eqn: sim]0 까지는 출력으로 설정 */

PORTB.3 = 1;

OPTION.RBPU = 0;	/* 내부 풀업으로 설정 */

if(SW4 == 0)	/* 외부의 스위치가 접지와 연결되었을 때 */

team = TEAM_A;

else	/* 스위치가 접지와 연결되지 않았을 때 */

team = TEAM_B;

위에서 설명한 PIC16C73의 기능을 이용하면 축구로봇을 위한 기본적인 로봇 프로그램을 완성할 수 있다. 실제 로봇을 움직이기 위한 전술 전략은 주컴퓨터에서 처리하며 이들에 대해서는 이후에 있을 교육내용에 들어갈 예정이다.